package com.example.demo.service.impl;

import cn.hutool.core.io.FastByteArrayOutputStream;
import cn.hutool.core.io.IoUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.example.demo.dao.BookMapper;
 import com.example.demo.model.Book;
import com.example.demo.service.DownloadNovel;
import com.example.demo.service.impl.DeafultParseContentPage;
import com.example.demo.service.impl.DefaultParseInfoPage;
import com.example.demo.util.HttpUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * 功能描述：
 * DownloadNovel的抽象类
 *
 * @Author: Zhanghf
 * @Date: 2021/12/11 20:05
 */
public abstract class DefaultDownloadNovel implements DownloadNovel {
    @Autowired
    DefaultParseInfoPage parseInfoPage;
    @Autowired
    DeafultParseContentPage parseContentPage;
    @Autowired
    HttpUtils httpUtils;
    @Autowired
    BookMapper bookMapper;

    String sourceName;

    ArrayList<String> chapterlist;

    /**
     * @param bookurl     小说url
     * @param imageprefix 小说封面地址前缀
     * @param sourceName  源站网名
     * @Author Zhanghf
     * @Date 2021-12-12 17:00
     * @Description:爬取小说的逻辑，包括对异常情况的处理
     * @Return:
     */

    public void downloadLogic(String bookurl, String imageprefix, String sourceName) throws IOException {
        this.sourceName = sourceName;
        //sql优化
        //  Book book = bookMapper.selectOne(new QueryWrapper<Book>().eq("url", bookurl));
//        根据url查，只查两个字段 id,pic
        Book book = bookMapper.selectOne(new QueryWrapper<Book>().eq("url", bookurl).select("id", "pic"));

        Integer bookid = book.getId();
//        解析目录，并爬取章节
        parseInfoPage.parseCatalogue(bookurl, bookid);
        //图片的爬取不分源站，爬到就OK；图书文字的爬取分不同源站

        if (book.getPic() == null) {
            String image = httpUtils.getImage(imageprefix + parseInfoPage.imgsrc, bookid);
            bookMapper.update(null, new UpdateWrapper<Book>().eq("id", bookid).set("pic", 1));
        }

//        章节文本路径
        String chapterfiles = "C:\\Knight2.0\\" + sourceName + "\\" + bookid;
//        小说完整Txt路径
        String completefiles = "C:\\Knight2.0\\complete\\" + sourceName;

        File dir = new File(chapterfiles);
        File fileConmplete = new File(completefiles + "\\bookid.txt");

        //dir存在
        File[] files = dir.listFiles();

//        章节文本文件夹不存在
        try {
            int fileslength = files.length;
        } catch (NullPointerException e) {
            dir.mkdirs();
            files = dir.listFiles();
        }
        ArrayList<String> urllist = parseInfoPage.urllist;
        chapterlist = parseInfoPage.chapterlist;
        //文件夹中不存在txt文件


        if (files.length == 0) {
            //不存在章节内容，但有完整内容，可能误删
            if (fileConmplete.exists()) {
                fileConmplete.delete();
            }

            bookMapper.update(null, new UpdateWrapper<Book>().eq("id", bookid).set("introduction", parseInfoPage.introduction));

            //章节从1开始
            for (int i = 1; i <= urllist.size(); i++) {
                parseContentPage.parseContent(bookurl + urllist.get(i - 1));
                String beforereplace = parseContentPage.beforereplace;
                String afterreplace = parseContentPage.afterreplace;

                writerTochapter(chapterfiles, beforereplace, bookid, i);
                writerTocomplete(completefiles, afterreplace, bookid, parseContentPage.sectiontitle);

                bookMapper.update(null, new UpdateWrapper<Book>().eq("id", bookid).
                        set("latestdate", new Date()).
                        set("latesthref", urllist.get(i - 1)).
                        set("latestnum", i).
                        set("latestchapter", chapterlist.get(i - 1)))
                ;
            }
            System.out.println("下载至服务器-----完成");
            return;

            //之前不加return，会继续向下运行
            //继续向下运行之后，由于File对象dir创建时对应的文件夹内没有文件，即fileList=0，影响接下来的一系列判断，，导致在complete\\txt文件中小说爬取了两次
            // 对File类的理解
            // File 类是对文件系统的映射 并不是硬盘上真实的文件，所以文件/文件夹出现变化时，File对象并不会随之变化
        }

        //存在
        List<File> fileList = Arrays.asList(files);
        Integer i;

        List<String> fileNames = new ArrayList<>();

        for (int i1 = 0; i1 < fileList.size(); i1++) {
            fileNames.add(fileList.get(i1).getName());
        }

        for (i = 1; i <= fileList.size(); i++) {
            if (!fileNames.contains(i + ".txt")) {
                break;
            }
        }

        //判断文件名是否符合从1--n依次递增的顺序
        //不符合
        if (!i.equals(Integer.parseInt(fileList.get(fileList.size()-1).getName().replace(".txt","")) + 1)) {
            for (int i1 = 1; i1 <= fileList.size(); i1++) {
                fileList.get(i1 - 1).delete();
            }
            if (fileConmplete.exists()) {
                fileConmplete.delete();
            }
            downloadLogic(bookurl, imageprefix + parseInfoPage.imgsrc, sourceName);
        } else {

            // 查询数据表中latestnum字段存储的与文件夹存储的文件数是否一致
            //  优化前
            List<Object> objects = bookMapper.selectObjs(new QueryWrapper<Book>().eq("id", bookid).select("latestnum"));
            Integer booklatestnum = (Integer) objects.get(0);

            //如果不一致，从文件夹存储的章节开始继续爬取至最新章节到本地，并更新字段
            if (booklatestnum == null || !booklatestnum.equals(fileList.size())) {
                for (i = fileList.size() + 1; i <= urllist.size(); i++) {
                    parseContentPage.parseContent(bookurl + urllist.get(i - 1));
                    String beforereplace = parseContentPage.beforereplace;
                    String afterreplace = parseContentPage.afterreplace;
                    writerTochapter(chapterfiles, beforereplace, bookid, i);
                    writerTocomplete(completefiles, afterreplace, bookid, parseContentPage.sectiontitle);

                    bookMapper.update(null, new UpdateWrapper<Book>().eq("id", bookid).
                            set("latestdate", new Date()).
                            set("latesthref", urllist.get(i - 1)).
                            set("latestnum", i).
                            set("latestchapter", chapterlist.get(i - 1)));
                    System.out.println("下载至服务器-----完成");
                    return;
                }
            } else
            //如果一致，查询存储的章节是否为最新章节
            {
                //如果不是，从文件夹存储的章节开始继续爬取至最新章节到本地，并更新字段
                if (urllist.size() != fileList.size()) {

                    //  优化前
                    //  bookMapper.update(null,new UpdateWrapper<Book>().eq("url",bookurl).set("introduction",introduction));
                    for (i = fileList.size() + 1; i <= urllist.size(); i++) {
                        parseContentPage.parseContent(bookurl + urllist.get(i - 1));
                        String beforereplace = parseContentPage.beforereplace;
                        String afterreplace = parseContentPage.afterreplace;
                        writerTochapter(chapterfiles, beforereplace, bookid, i);
                        writerTocomplete(completefiles, afterreplace, bookid, parseContentPage.sectiontitle);

                        //    优化前
                        //   bookMapper.update(null,new UpdateWrapper<Book>().eq("url",bookurl).set("latestdate",new Date()).set("latesthref",urllist.get(i-1)).set("latestnum",i));
                        bookMapper.update(null, new UpdateWrapper<Book>().eq("id", bookid).
                                set("latestdate", new Date()).
                                set("latesthref", urllist.get(i - 1)).
                                set("latestnum", i).
                                set("latestchapter", chapterlist.get(i - 1)));
                    }
                    System.out.println("下载至服务器-----完成");
                    return;
                } else {
                    //不存在完整内容，但章节内容完整，可能误删
                    if (!fileConmplete.exists()) {
                        for (i = 1; i <= urllist.size(); i++) {
                            parseContentPage.parseContent(bookurl + urllist.get(i - 1));
                            String afterreplace = parseContentPage.afterreplace;

                            writerTocomplete(completefiles, afterreplace, bookid, parseContentPage.sectiontitle);


                        }
                        System.out.println("服务器已存在该小说，可直接下载");
                    } else {
                        System.out.println("服务器已存在该小说，可直接下载");

                    }
                }
                //如果是，结束
            }
        }
    }


    ;

    public void writerTochapter(String path, String content, Integer bookid, Integer chapterid) throws IOException {
        FileWriter writerTochapter = new FileWriter(
                path + "\\" +
                        chapterid + ".txt", true);
        BufferedWriter bufferedWriter = new BufferedWriter(writerTochapter);
        bufferedWriter.write(content);
        bufferedWriter.flush();
    }

    public void writerTocomplete(String path, String content, Integer bookid, String sectiontitle) throws IOException {
//        sql优化
//        Book book = bookMapper.selectById(bookid);
        Book book = bookMapper.selectOne(new QueryWrapper<Book>().eq("id", bookid).select("latestnum", "latestchapter"));
        String latestchapter;
        Integer Latestnum;
        File dirfile = new File("C:\\Knight2.0\\" + sourceName + "\\" + bookid);
        File[] files = dirfile.listFiles();

        if (book == null && files != null && files.length != 0) {
            //针对异常情况：有Txt文件，数据表中的记录除bookid外都被改为空
            latestchapter = chapterlist.get(files.length - 1);
            Latestnum = files.length;
        } else {
            latestchapter = book.getLatestchapter();
            Latestnum = book.getLatestnum();
        }

        File file = new File(path + "\\" + bookid + ".txt");
        FileInputStream fileInputStream = null;
//        先判断File是否存在  ；  先创建输入流，出现异常再trycatch
//        想想还是后者好，前者每次都需要判断，其实只有第一次不存在，其他情况都存在
//        妙
        try {
            fileInputStream = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            try {
                file.createNewFile();
                fileInputStream = new FileInputStream(file);
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        FastByteArrayOutputStream read = IoUtil.read(fileInputStream);

        FileInputStream latestinputstream = new FileInputStream(new File(
                "C:\\Knight2.0\\" + sourceName + "\\" + bookid + "\\" + Latestnum + ".txt"));
        //第一次爬取章节，file还没创建，可能为空 || 完整小说的txt文件包含爬取的最后一个章节
        if (latestinputstream == null || read.toString().contains(latestchapter)) {
            FileWriter writerTocomplete = null;
            try {
                writerTocomplete = new FileWriter(
                        file, true);
            } catch (IOException e) {
                e.printStackTrace();
            }
            BufferedWriter bufferedWriters = new BufferedWriter(writerTocomplete);
            bufferedWriters.write(sectiontitle);
            bufferedWriters.newLine();
            bufferedWriters.write(content);
            bufferedWriters.flush();
        } else {
            //对异常情况：爬取的最后一章没有追加到完整小说txt文件进行处理
            String latesttext = IoUtil.readUtf8(latestinputstream);
            String replace = latesttext.replace("<br>", "").replace("&nbsp;", " ");
            FileWriter writerTocomplete = new FileWriter(
                    file, true);
            BufferedWriter bufferedWriters = new BufferedWriter(writerTocomplete);
            bufferedWriters.write(chapterlist.get(Latestnum - 1));
            bufferedWriters.newLine();
            bufferedWriters.write(replace);
            bufferedWriters.newLine();
            bufferedWriters.write(sectiontitle);
            bufferedWriters.newLine();
            bufferedWriters.write(content);
            bufferedWriters.flush();
        }

    }
}

